#include "stdafx.h"
#include "../vfs/PathFwd.h"
#include "../vfs/ILocation.h"
#include "../vfs/IDirectory.h"
#include "../vfs/VirtualProfile.h"

/*
class vfs::VirtualProfile::IterImpl : public vfs::VirtualProfile::Iterator::IImplementation
{
	friend class vfs::VirtualProfile;
	typedef vfs::VirtualProfile::Iterator::IImplementation tBaseClass;

	IterImpl(VirtualProfile* profile) : tBaseClass(), m_profile(profile)
	{
		THROWIFFALSE(profile, L"");
		// only unique locations
		_loc_iter = m_profile->m_setLocations.begin();
	}
public:
	IterImpl() : tBaseClass(), m_profile(NULL)
	{};
	virtual ~IterImpl()
	{};
	//////
	virtual vfs::ILocation*		value()
	{
		if(_loc_iter != m_profile->m_setLocations.end())
		{
			return *_loc_iter;
		}
		return NULL;
	}
	virtual void					next()
	{
		if(_loc_iter != m_profile->m_setLocations.end())
		{
			_loc_iter++;
		}
	}
protected:
	virtual tBaseClass* clone()
	{
		IterImpl* iter = new IterImpl();
		iter->m_profile = m_profile;
		iter->_loc_iter = _loc_iter;
		return iter;
	}
private:
	vfs::VirtualProfile*						m_profile;
	vfs::VirtualProfile::tUniqueLoc::iterator	_loc_iter;
};

//------------------------------//

class vfs::VirtualProfile::FileIterImpl : public vfs::VirtualProfile::FileIterator::IImplementation
{
	friend class vfs::VirtualProfile;
	typedef vfs::VirtualProfile::FileIterator::IImplementation tBaseClass;
	FileIterImpl(vfs::Path const& sPattern, VirtualProfile* profile);

public:
	FileIterImpl() : tBaseClass(), m_profile(NULL)
	{};
	virtual ~FileIterImpl()
	{};
	/////
	virtual vfs::BaseFile*			value()
	{
		return file;
	}
	virtual void					next();
protected:
	virtual tBaseClass* clone()
	{
		FileIterImpl* iter2 = new FileIterImpl();
		iter2->m_pattern = m_pattern;
		iter2->m_profile = m_profile;
		iter2->iter = iter;
		iter2->fiter = fiter;
		iter2->file = file;
		return iter2;
	}
private:
	vfs::Path						m_pattern;
	vfs::VirtualProfile*			m_profile;
	vfs::VirtualProfile::Iterator	iter;
	vfs::Location::Iterator	fiter;
	vfs::BaseFile*					file;
};

vfs::VirtualProfile::FileIterImpl::FileIterImpl(vfs::Path const& sPattern, VirtualProfile* profile)
: tBaseClass(), m_pattern(sPattern), m_profile(profile)
{
	THROWIFFALSE(profile, L"");
	iter = m_profile->begin();
	while(!iter.end())
	{
		fiter = iter.value()->begin();
		while(!fiter.end())
		{
			file = fiter.value();
			if( matchPattern(m_pattern(), file->getPath()()) )
			{
				return;
			}
			fiter.next();
		}
		iter.next();
	}
	file = NULL;
}

void vfs::VirtualProfile::FileIterImpl::next()
{
	if(!fiter.end())
	{
		fiter.next();
	}
	while(!iter.end())
	{
		while(!fiter.end())
		{
			file = fiter.value();
			if( matchPattern(m_pattern(), file->getPath()()) )
			{
				return;
			}
			fiter.next();
		}
		iter.next();
		if(!iter.end())
		{
			fiter = iter.value()->begin();
		}
	}
	file = NULL;
}
*/

//---------------------------------------//

namespace ja2{ namespace vfs
{

	VirtualProfile::VirtualProfile(std::string const &ProfileName, bool bWritable)
		: m_Name(ProfileName), m_Writable(bWritable)
	{
	}

	bool VirtualProfile::location_exists(boost::filesystem::path const &Path) const
	{
		return (m_Locations.count(Path) == 1);
	}

	void VirtualProfile::add_location(ILocationPtr_t &&pLoc)
	{
//		m_setLocations.insert(pLoc);
		// Get all sub-directories of location
//		PathVector_t const subdirs = pLoc->get_sub_dirs();
		for(auto it = pLoc->begin(), end = pLoc->end(); it != end; ++it)
		{
			// Location exist
			if(location_exists((*it)->get_path()))
				throw RuntimeException("Location already taken.");
			// Add location
			else
				m_Locations[(*it)->get_path()] = std::move(pLoc);
		}
	}

	bool VirtualProfile::is_writeable() const
	{
		return m_Writable;
	}

	ILocation *VirtualProfile::get_location(boost::filesystem::path const &Path) const
	{
		return m_Locations.find(Path)->second.get();
	}

	std::string const &VirtualProfile::get_name() const
	{
		return m_Name;
	}

/*
	vfs::VirtualProfile::Iterator vfs::VirtualProfile::begin()
	{
		return Iterator(new IterImpl(this));
	}

	vfs::VirtualProfile::FileIterator vfs::VirtualProfile::files(vfs::Path const& sPattern)
	{
		return FileIterator( new FileIterImpl(sPattern, this));
	}

	

	vfs::ILocation* vfs::VirtualProfile::getLocation(vfs::Path const& sPath) const
	{
		tLocations::const_iterator it = m_Locations.find(sPath);
		if(it != m_Locations.end())
		{
			return it->second;
		}
		return NULL;
	}

	vfs::BaseFile* vfs::VirtualProfile::getFile(vfs::Path const& sPath) const
	{
		vfs::Path sDir,sFile;
		sPath.splitLast(sDir,sFile);
		tLocations::const_iterator it = m_Locations.find(sDir);
		if(it != m_Locations.end())
		{
			return it->second->getFile(sPath);
		}
		return NULL;
	}


	//----------------------------------------//

	class vfs::CProfileStack::IterImpl : public vfs::CProfileStack::Iterator::IImplementation
	{
		friend class CProfileStack;
		typedef CProfileStack::Iterator::IImplementation tBaseClass;

		IterImpl(CProfileStack* pPStack) : tBaseClass(), m_pPStack(pPStack)
		{
			THROWIFFALSE(m_pPStack, L"");
			_prof_iter = m_pPStack->m_profiles.begin();
		}
	public:
		IterImpl() : tBaseClass(), m_pPStack(NULL)
		{};
		~IterImpl()
		{};
		//////
		virtual vfs::VirtualProfile*	value()
		{
			if(_prof_iter != m_pPStack->m_profiles.end())
			{
				return *_prof_iter;
			}
			return NULL;
		}
		virtual void					next()
		{
			if(_prof_iter != m_pPStack->m_profiles.end())
			{
				_prof_iter++;
			}
		}
	protected:
		virtual tBaseClass* clone()
		{
			IterImpl* iter = new IterImpl();
			iter->m_pPStack = m_pPStack;
			iter->_prof_iter = _prof_iter;
			return iter;
		}
	private:
		vfs::CProfileStack*							m_pPStack;
		std::list<vfs::VirtualProfile*>::iterator	_prof_iter;
	};

	//---------------------------------//
	
	vfs::CProfileStack::CProfileStack()
	{
	}

	vfs::CProfileStack::~CProfileStack()
	{
		std::list<VirtualProfile*>::iterator it = m_profiles.begin();
		for(; it != m_profiles.end(); ++it)
		{
			delete (*it);
			(*it) = NULL;
		}
		m_profiles.clear();
	}

	vfs::VirtualProfile* vfs::CProfileStack::getProfile(utf8string const& sName) const
	{
		std::list<VirtualProfile*>::const_iterator it = m_profiles.begin();
		for(;it != m_profiles.end(); ++it)
		{
			if( StrCmp::EqualCase((*it)->m_Name, sName) )
			{
				return *it;
			}
		}
		return NULL;
	}

	vfs::VirtualProfile* vfs::CProfileStack::getWriteProfile()
	{
		std::list<vfs::VirtualProfile*>::const_iterator it = m_profiles.begin();
		for(;it != m_profiles.end(); ++it)
		{
			if((*it)->m_Writable)
			{
				return *it;
			}
		}
		return NULL;
	}

	vfs::VirtualProfile* vfs::CProfileStack::topProfile() const
	{
		if(!m_profiles.empty())
		{
			return m_profiles.front();
		}
		return NULL;
	}

	bool vfs::CProfileStack::popProfile()
	{
		// there might be some files in this profile that are referenced in a CLog object
		// we need to it to release the file
		Log::flushAll();
		// an observer pattern would probably be the better solution,
		// but for now lets do it this way 

		vfs::VirtualProfile* prof = this->topProfile();
		if(prof)
		{
			vfs::VirtualProfile::Iterator loc_it = prof->begin();
			for(; !loc_it.end(); loc_it.next())
			{
				vfs::ILocation* loc = loc_it.value();
				vfs::ILocation::Iterator f_it = loc->begin();
				for(; !f_it.end(); f_it.next())
				{
					vfs::BaseFile* file = f_it.value();
					vfs::Path sDir, sFile;
					if(file)
					{
						file->getPath().splitLast(sDir,sFile);
						vfs::VirtualLocation* vloc = getVFS()->getVirtualLocation(sDir);
						if(vloc)
						{
							if( !vloc->removeFile(file) )
							{
								std::stringstream wss;
								wss << L"Could not remove file ["
									<< file->getPath()()
									<< L"] in Profile ["
									<< prof->m_Name << L"]";
								THROWEXCEPTION(wss.str().c_str());
							}
						}
						else
						{
							std::stringstream wss;
							wss << L"Virtual location [" << sDir() << L"] doesn't exist. Maybe the VFS was not properly setup.";
							THROWEXCEPTION(wss.str().c_str());
						}
					}
					else
					{
						std::stringstream wss;
						wss << L"File is NULL during iteration over files in location [" << loc->get_path()() << L"]";
						THROWEXCEPTION(wss.str().c_str());
					}
				}
			}
			// delete only when nothing went wrong
			this->m_profiles.pop_front();
			delete prof;
		}
		return true;
	}

	void vfs::CProfileStack::pushProfile(VirtualProfile* pProfile)
	{
		if(!getProfile(pProfile->m_Name))
		{
			m_profiles.push_front(pProfile);
			return;
		}
		THROWEXCEPTION(L"A profile with this name already exists");
	}

	vfs::CProfileStack::Iterator vfs::CProfileStack::begin()
	{
		return Iterator(new IterImpl(this));
	}
*/
} /*vfs*/} /*ja2*/